/*-------------------------------------------------------------------------
 *
 * llvmjit_deform.c
 *	  生成解构堆元组的代码。
 *
 * 这在编译时根据元组描述符的知识获得性能优势。可以利用固定列宽、NOT NULL等。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/backend/jit/llvm/llvmjit_deform.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <llvm-c/Core.h>

#include "access/htup_details.h"
#include "access/tupdesc_details.h"
#include "executor/tuptable.h"
#include "jit/llvmjit.h"
#include "jit/llvmjit_emit.h"


/*
 * 创建一个函数，该函数将类型描述的元组变形成 natts 列。
 */
LLVMValueRef slot_compile_deform(LLVMJitContext *fc_context, TupleDesc fc_desc,
					const TupleTableSlotOps *fc_ops, int fc_natts)
{
	char	   *fc_funcname;

	LLVMModuleRef fc_mod;
	LLVMContextRef fc_lc;
	LLVMBuilderRef fc_b;

	LLVMTypeRef fc_deform_sig;
	LLVMValueRef fc_v_deform_fn;

	LLVMBasicBlockRef fc_b_entry;
	LLVMBasicBlockRef fc_b_adjust_unavail_cols;
	LLVMBasicBlockRef fc_b_find_start;

	LLVMBasicBlockRef fc_b_out;
	LLVMBasicBlockRef fc_b_dead;
	LLVMBasicBlockRef *fc_attcheckattnoblocks;
	LLVMBasicBlockRef *fc_attstartblocks;
	LLVMBasicBlockRef *fc_attisnullblocks;
	LLVMBasicBlockRef *fc_attcheckalignblocks;
	LLVMBasicBlockRef *fc_attalignblocks;
	LLVMBasicBlockRef *fc_attstoreblocks;

	LLVMValueRef fc_v_offp;

	LLVMValueRef fc_v_tupdata_base;
	LLVMValueRef fc_v_tts_values;
	LLVMValueRef fc_v_tts_nulls;
	LLVMValueRef fc_v_slotoffp;
	LLVMValueRef fc_v_flagsp;
	LLVMValueRef fc_v_nvalidp;
	LLVMValueRef fc_v_nvalid;
	LLVMValueRef fc_v_maxatt;

	LLVMValueRef fc_v_slot;

	LLVMValueRef fc_v_tupleheaderp;
	LLVMValueRef fc_v_tuplep;
	LLVMValueRef fc_v_infomask1;
	LLVMValueRef fc_v_infomask2;
	LLVMValueRef fc_v_bits;

	LLVMValueRef fc_v_hoff;

	LLVMValueRef fc_v_hasnulls;

	/* 最后一列（0 索引）保证存在 */
	int			fc_guaranteed_column_number = -1;

	/* 当前已知的对齐方式 */
	int			fc_known_alignment = 0;

	/* 如果为真，known_alignment 描述列的确切偏移量 */
	bool		fc_attguaranteedalign = true;

	int			fc_attnum;

	/* 虚拟元组不需要变形，因此不生成代码 */
	if (fc_ops == &TTSOpsVirtual)
		return NULL;

	/* 拒绝对我们不知道如何处理的槽类型进行即时编译 */
	if (fc_ops != &TTSOpsHeapTuple && fc_ops != &TTSOpsBufferHeapTuple &&
		fc_ops != &TTSOpsMinimalTuple)
		return NULL;

	fc_mod = llvm_mutable_module(fc_context);
	fc_lc = LLVMGetModuleContext(fc_mod);

	fc_funcname = llvm_expand_funcname(fc_context, "deform");

	/*
	 * 检查哪些列必须存在，以便我们不必不必要地检查行的
	 * natts。
	 */
	for (fc_attnum = 0; fc_attnum < fc_desc->natts; fc_attnum++)
	{
		Form_pg_attribute fc_att = TupleDescAttr(fc_desc, fc_attnum);

		/*
		 * 如果列声明为 NOT NULL，则必须在每个元组中出现，
		 * 除非有一个“缺失”条目可以为其提供非 NULL 值。
		 * 这反过来保证了 NULL 位图 - 如果有任何可 NULL 的列 -
		 * 至少足够长以覆盖到 attnum 的列。
		 *
		 * 要小心，尽管 attisdropped && attnotnull 的组合不应该
		 * 存在，但仍要检查 !attisdropped。
		 */
		if (fc_att->attnotnull &&
			!fc_att->atthasmissing &&
			!fc_att->attisdropped)
			fc_guaranteed_column_number = fc_attnum;
	}

	/* 创建签名和函数 */
	{
		LLVMTypeRef fc_param_types[1];

		fc_param_types[0] = l_ptr(StructTupleTableSlot);

		fc_deform_sig = LLVMFunctionType(LLVMVoidTypeInContext(fc_lc),
									  fc_param_types, lengthof(fc_param_types), 0);
	}
	fc_v_deform_fn = LLVMAddFunction(fc_mod, fc_funcname, fc_deform_sig);
	LLVMSetLinkage(fc_v_deform_fn, LLVMInternalLinkage);
	LLVMSetParamAlignment(LLVMGetParam(fc_v_deform_fn, 0), MAXIMUM_ALIGNOF);
	llvm_copy_attributes(AttributeTemplate, fc_v_deform_fn);

	fc_b_entry =
		LLVMAppendBasicBlockInContext(fc_lc, fc_v_deform_fn, "entry");
	fc_b_adjust_unavail_cols =
		LLVMAppendBasicBlockInContext(fc_lc, fc_v_deform_fn, "adjust_unavail_cols");
	fc_b_find_start =
		LLVMAppendBasicBlockInContext(fc_lc, fc_v_deform_fn, "find_startblock");
	fc_b_out =
		LLVMAppendBasicBlockInContext(fc_lc, fc_v_deform_fn, "outblock");
	fc_b_dead =
		LLVMAppendBasicBlockInContext(fc_lc, fc_v_deform_fn, "deadblock");

	fc_b = LLVMCreateBuilderInContext(fc_lc);

	fc_attcheckattnoblocks = palloc(sizeof(LLVMBasicBlockRef) * fc_natts);
	fc_attstartblocks = palloc(sizeof(LLVMBasicBlockRef) * fc_natts);
	fc_attisnullblocks = palloc(sizeof(LLVMBasicBlockRef) * fc_natts);
	fc_attcheckalignblocks = palloc(sizeof(LLVMBasicBlockRef) * fc_natts);
	fc_attalignblocks = palloc(sizeof(LLVMBasicBlockRef) * fc_natts);
	fc_attstoreblocks = palloc(sizeof(LLVMBasicBlockRef) * fc_natts);

	fc_known_alignment = 0;

	LLVMPositionBuilderAtEnd(fc_b, fc_b_entry);

	/* 首先执行分配，llvm 只会将这些转换为寄存器 */
	fc_v_offp = LLVMBuildAlloca(fc_b, TypeSizeT, "v_offp");

	fc_v_slot = LLVMGetParam(fc_v_deform_fn, 0);

	fc_v_tts_values =
		l_load_struct_gep(fc_b, StructTupleTableSlot, fc_v_slot, FIELDNO_TUPLETABLESLOT_VALUES,
						  "tts_values");
	fc_v_tts_nulls =
		l_load_struct_gep(fc_b, StructTupleTableSlot, fc_v_slot, FIELDNO_TUPLETABLESLOT_ISNULL,
						  "tts_ISNULL");
	fc_v_flagsp = l_struct_gep(fc_b, StructTupleTableSlot, fc_v_slot, FIELDNO_TUPLETABLESLOT_FLAGS, "");
	fc_v_nvalidp = l_struct_gep(fc_b, StructTupleTableSlot, fc_v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");

	if (fc_ops == &TTSOpsHeapTuple || fc_ops == &TTSOpsBufferHeapTuple)
	{
		LLVMValueRef fc_v_heapslot;

		fc_v_heapslot =
			LLVMBuildBitCast(fc_b,
							 fc_v_slot,
							 l_ptr(StructHeapTupleTableSlot),
							 "heapslot");
		fc_v_slotoffp = l_struct_gep(fc_b, StructHeapTupleTableSlot, fc_v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_OFF, "");
		fc_v_tupleheaderp =
			l_load_struct_gep(fc_b, StructHeapTupleTableSlot, fc_v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_TUPLE,
							  "tupleheader");
	}
	else if (fc_ops == &TTSOpsMinimalTuple)
	{
		LLVMValueRef fc_v_minimalslot;

		fc_v_minimalslot =
			LLVMBuildBitCast(fc_b,
							 fc_v_slot,
							 l_ptr(StructMinimalTupleTableSlot),
							 "minimalslot");
		fc_v_slotoffp = l_struct_gep(fc_b,
								  StructMinimalTupleTableSlot,
								  fc_v_minimalslot,
								  FIELDNO_MINIMALTUPLETABLESLOT_OFF, "");
		fc_v_tupleheaderp =
			l_load_struct_gep(fc_b,
							  StructMinimalTupleTableSlot,
							  fc_v_minimalslot,
							  FIELDNO_MINIMALTUPLETABLESLOT_TUPLE,
							  "tupleheader");
	}
	else
	{
		/* 应该在函数开始时返回 */
		pg_unreachable();
	}

	fc_v_tuplep =
		l_load_struct_gep(fc_b,
						  StructHeapTupleData,
						  fc_v_tupleheaderp,
						  FIELDNO_HEAPTUPLEDATA_DATA,
						  "tuple");
	fc_v_bits =
		LLVMBuildBitCast(fc_b,
						 l_struct_gep(fc_b,
									  StructHeapTupleHeaderData,
									  fc_v_tuplep,
									  FIELDNO_HEAPTUPLEHEADERDATA_BITS,
									  ""),
						 l_ptr(LLVMInt8TypeInContext(fc_lc)),
						 "t_bits");
	fc_v_infomask1 =
		l_load_struct_gep(fc_b,
						  StructHeapTupleHeaderData,
						  fc_v_tuplep,
						  FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK,
						  "infomask1");
	fc_v_infomask2 =
		l_load_struct_gep(fc_b,
						  StructHeapTupleHeaderData,
						  fc_v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2,
						  "infomask2");

	/* t_infomask & HEAP_HASNULL */
	fc_v_hasnulls =
		LLVMBuildICmp(fc_b, LLVMIntNE,
					  LLVMBuildAnd(fc_b,
								   l_int16_const(fc_lc, HEAP_HASNULL),
								   fc_v_infomask1, ""),
					  l_int16_const(fc_lc, 0),
					  "hasnulls");

	/* t_infomask2 & HEAP_NATTS_MASK */
	fc_v_maxatt = LLVMBuildAnd(fc_b,
							l_int16_const(fc_lc, HEAP_NATTS_MASK),
							fc_v_infomask2,
							"maxatt");

	/*
	 * 需要进行扩展，因为 getelementptr 否则将 hoff 视为带符号的 8 位
	 * 整数，如果 t_hoff > 127，将产生负偏移。
	 */
	fc_v_hoff =
		LLVMBuildZExt(fc_b,
					  l_load_struct_gep(fc_b,
										StructHeapTupleHeaderData,
										fc_v_tuplep,
										FIELDNO_HEAPTUPLEHEADERDATA_HOFF,
										""),
					  LLVMInt32TypeInContext(fc_lc), "t_hoff");

	fc_v_tupdata_base = l_gep(fc_b,
						   LLVMInt8TypeInContext(fc_lc),
						   LLVMBuildBitCast(fc_b,
											fc_v_tuplep,
											l_ptr(LLVMInt8TypeInContext(fc_lc)),
											""),
						   &fc_v_hoff, 1,
						   "v_tupdata_base");

	/*
	 * 从槽加载元组起始偏移量。如果槽中没有现有的变形列，将在
	 * 下面重置。
	 */
	{
		LLVMValueRef fc_v_off_start;

		fc_v_off_start = l_load(fc_b, LLVMInt32TypeInContext(fc_lc), fc_v_slotoffp, "v_slot_off");
		fc_v_off_start = LLVMBuildZExt(fc_b, fc_v_off_start, TypeSizeT, "");
		LLVMBuildStore(fc_b, fc_v_off_start, fc_v_offp);
	}

	/* 为每个属性构建基本块，需要它们作为跳转目标 */
	for (fc_attnum = 0; fc_attnum < fc_natts; fc_attnum++)
	{
		fc_attcheckattnoblocks[fc_attnum] =
			l_bb_append_v(fc_v_deform_fn, "block.attr.%d.attcheckattno", fc_attnum);
		fc_attstartblocks[fc_attnum] =
			l_bb_append_v(fc_v_deform_fn, "block.attr.%d.start", fc_attnum);
		fc_attisnullblocks[fc_attnum] =
			l_bb_append_v(fc_v_deform_fn, "block.attr.%d.attisnull", fc_attnum);
		fc_attcheckalignblocks[fc_attnum] =
			l_bb_append_v(fc_v_deform_fn, "block.attr.%d.attcheckalign", fc_attnum);
		fc_attalignblocks[fc_attnum] =
			l_bb_append_v(fc_v_deform_fn, "block.attr.%d.align", fc_attnum);
		fc_attstoreblocks[fc_attnum] =
			l_bb_append_v(fc_v_deform_fn, "block.attr.%d.store", fc_attnum);
	}

	/*
	 * 检查是否确保所有需要的属性在元组中可用（但仍可能为 NULL），
	 * 这要归功于最后一个待变形列为 NOT NULL，或者后续的不在这里访问
	 * 的列为 NOT NULL。 如果这不能保证，则必须检查元组头的 natt，
	 * 并且可能需要提取缺失的属性（使用 slot_getmissingattrs()）。
	 */
	if ((fc_natts - 1) <= fc_guaranteed_column_number)
	{
		/* 仅跳过不必要的块 */
		LLVMBuildBr(fc_b, fc_b_adjust_unavail_cols);
		LLVMPositionBuilderAtEnd(fc_b, fc_b_adjust_unavail_cols);
		LLVMBuildBr(fc_b, fc_b_find_start);
	}
	else
	{
		LLVMValueRef fc_v_params[3];
		LLVMValueRef fc_f;

		/* 如果未提供所有列，则分支 */
		LLVMBuildCondBr(fc_b,
						LLVMBuildICmp(fc_b, LLVMIntULT,
									  fc_v_maxatt,
									  l_int16_const(fc_lc, fc_natts),
									  ""),
						fc_b_adjust_unavail_cols,
						fc_b_find_start);

		/* 如果没有，将相关列的 tts_isnull 设为 true */
		LLVMPositionBuilderAtEnd(fc_b, fc_b_adjust_unavail_cols);

		fc_v_params[0] = fc_v_slot;
		fc_v_params[1] = LLVMBuildZExt(fc_b, fc_v_maxatt, LLVMInt32TypeInContext(fc_lc), "");
		fc_v_params[2] = l_int32_const(fc_lc, fc_natts);
		fc_f = llvm_pg_func(fc_mod, "slot_getmissingattrs");
		l_call(fc_b,
			   LLVMGetFunctionType(fc_f), fc_f,
			   fc_v_params, lengthof(fc_v_params), "");
		LLVMBuildBr(fc_b, fc_b_find_start);
	}

	LLVMPositionBuilderAtEnd(fc_b, fc_b_find_start);

	fc_v_nvalid = l_load(fc_b, LLVMInt16TypeInContext(fc_lc), fc_v_nvalidp, "");

	/*
	 * 建立从 nvalid 跳转到正确的 startblock 的 switch。
	 * 调用者当前没有这样的知识，但在已知槽为空（例如在扫描
	 * 节点中）时避免此检查将对性能有好处。
	 */
	if (true)
	{
		LLVMValueRef fc_v_switch = LLVMBuildSwitch(fc_b, fc_v_nvalid,
												fc_b_dead, fc_natts);

		for (fc_attnum = 0; fc_attnum < fc_natts; fc_attnum++)
		{
			LLVMValueRef fc_v_attno = l_int16_const(fc_lc, fc_attnum);

			LLVMAddCase(fc_v_switch, fc_v_attno, fc_attcheckattnoblocks[fc_attnum]);
		}
	}
	else
	{
		/* 从入口块跳转到第一个块 */
		LLVMBuildBr(fc_b, fc_attcheckattnoblocks[0]);
	}

	LLVMPositionBuilderAtEnd(fc_b, fc_b_dead);
	LLVMBuildUnreachable(fc_b);

	/*
	 * 遍历每个需要变形的属性，构建变形的代码。
	 */
	for (fc_attnum = 0; fc_attnum < fc_natts; fc_attnum++)
	{
		Form_pg_attribute fc_att = TupleDescAttr(fc_desc, fc_attnum);
		LLVMValueRef fc_v_incby;
		int			fc_alignto;
		LLVMValueRef fc_l_attno = l_int16_const(fc_lc, fc_attnum);
		LLVMValueRef fc_v_attdatap;
		LLVMValueRef fc_v_resultp;

		/* 构建检查是否完成所有必要属性的块 */
		LLVMPositionBuilderAtEnd(fc_b, fc_attcheckattnoblocks[fc_attnum]);

		/*
		 * 如果这是第一个属性，slot->tts_nvalid 为 0。因此
		 * 也将偏移量重置为 0，它可能来自于之前的执行。
		 */
		if (fc_attnum == 0)
		{
			LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_offp);
		}

		/*
		 * 构建检查列是否可用（即元组是否存储了那么多列）。
		 * 如果我们知道有后续的 NOT NULL 列，可以避免这个分支。
		 */
		if (fc_attnum <= fc_guaranteed_column_number)
		{
			LLVMBuildBr(fc_b, fc_attstartblocks[fc_attnum]);
		}
		else
		{
			LLVMValueRef fc_v_islast;

			fc_v_islast = LLVMBuildICmp(fc_b, LLVMIntUGE,
									 fc_l_attno,
									 fc_v_maxatt,
									 "heap_natts");
			LLVMBuildCondBr(fc_b, fc_v_islast, fc_b_out, fc_attstartblocks[fc_attnum]);
		}
		LLVMPositionBuilderAtEnd(fc_b, fc_attstartblocks[fc_attnum]);

		/*
		 * 如果必要，检查 NULL。无需考虑缺失的属性，
		 * 因为如果它们存在，heaptuple 的 natts
		 * 将指示需要 slot_getmissingattrs()。
		 */
		if (!fc_att->attnotnull)
		{
			LLVMBasicBlockRef fc_b_ifnotnull;
			LLVMBasicBlockRef fc_b_ifnull;
			LLVMBasicBlockRef fc_b_next;
			LLVMValueRef fc_v_attisnull;
			LLVMValueRef fc_v_nullbyteno;
			LLVMValueRef fc_v_nullbytemask;
			LLVMValueRef fc_v_nullbyte;
			LLVMValueRef fc_v_nullbit;

			fc_b_ifnotnull = fc_attcheckalignblocks[fc_attnum];
			fc_b_ifnull = fc_attisnullblocks[fc_attnum];

			if (fc_attnum + 1 == fc_natts)
				fc_b_next = fc_b_out;
			else
				fc_b_next = fc_attcheckattnoblocks[fc_attnum + 1];

			fc_v_nullbyteno = l_int32_const(fc_lc, fc_attnum >> 3);
			fc_v_nullbytemask = l_int8_const(fc_lc, 1 << ((fc_attnum) & 0x07));
			fc_v_nullbyte = l_load_gep1(fc_b, LLVMInt8TypeInContext(fc_lc), fc_v_bits, fc_v_nullbyteno, "attnullbyte");

			fc_v_nullbit = LLVMBuildICmp(fc_b,
									  LLVMIntEQ,
									  LLVMBuildAnd(fc_b, fc_v_nullbyte, fc_v_nullbytemask, ""),
									  l_int8_const(fc_lc, 0),
									  "attisnull");

			fc_v_attisnull = LLVMBuildAnd(fc_b, fc_v_hasnulls, fc_v_nullbit, "");

			LLVMBuildCondBr(fc_b, fc_v_attisnull, fc_b_ifnull, fc_b_ifnotnull);

			LLVMPositionBuilderAtEnd(fc_b, fc_b_ifnull);

			/* 存储 null 字节 */
			LLVMBuildStore(fc_b,
						   l_int8_const(fc_lc, 1),
						   l_gep(fc_b, LLVMInt8TypeInContext(fc_lc), fc_v_tts_nulls, &fc_l_attno, 1, ""));
			/* 存储零数据 */
			LLVMBuildStore(fc_b,
						   l_sizet_const(0),
						   l_gep(fc_b, TypeSizeT, fc_v_tts_values, &fc_l_attno, 1, ""));

			LLVMBuildBr(fc_b, fc_b_next);
			fc_attguaranteedalign = false;
		}
		else
		{
			/* 无需操作 */
			LLVMBuildBr(fc_b, fc_attcheckalignblocks[fc_attnum]);
			LLVMPositionBuilderAtEnd(fc_b, fc_attisnullblocks[fc_attnum]);
			LLVMBuildBr(fc_b, fc_attcheckalignblocks[fc_attnum]);
		}
		LLVMPositionBuilderAtEnd(fc_b, fc_attcheckalignblocks[fc_attnum]);

		/* 确定所需的对齐 */
		if (fc_att->attalign == TYPALIGN_INT)
			fc_alignto = ALIGNOF_INT;
		else if (fc_att->attalign == TYPALIGN_CHAR)
			fc_alignto = 1;
		else if (fc_att->attalign == TYPALIGN_DOUBLE)
			fc_alignto = ALIGNOF_DOUBLE;
		else if (fc_att->attalign == TYPALIGN_SHORT)
			fc_alignto = ALIGNOF_SHORT;
		else
		{
			elog(ERROR, "unknown alignment");
			fc_alignto = 0;
		}

		/* ------
		 * 即使需要对齐，如果可以证明不必要，也可以跳过：
		 * - 第一列保证已对齐
		 * - 跟随 NOT NULL 固定宽度数据的列已知
		 *   对齐，如果已知对齐与当前列兼容，可以跳过
		 *   对齐计算。
		 * ------
		 */
		if (fc_alignto > 1 &&
			(fc_known_alignment < 0 || fc_known_alignment != TYPEALIGN(fc_alignto, fc_known_alignment)))
		{
			/*
			 * 当访问一个 varlena 字段时，我们必须“窥视”一下，看看我们
			 * 是在查看一个填充字节还是一个 1 字节头数据的第一个字节。
			 * 零字节可以是填充字节，或者是对齐良好的 4 字节长度字的第一个字节；
			 * 在任一情况下，我们都可以安全对齐。非零字节必须是一个 1 字节
			 * 长度字，或者是对齐良好的 4 字节长度字的第一个字节；
			 * 在任一情况下，我们不需要对齐。
			 */
			if (fc_att->attlen == -1)
			{
				LLVMValueRef fc_v_possible_padbyte;
				LLVMValueRef fc_v_ispad;
				LLVMValueRef fc_v_off;

				/* 不知道是否为短的 varlena */
				fc_attguaranteedalign = false;

				fc_v_off = l_load(fc_b, TypeSizeT, fc_v_offp, "");

				fc_v_possible_padbyte =
					l_load_gep1(fc_b, LLVMInt8TypeInContext(fc_lc), fc_v_tupdata_base,
								fc_v_off, "padbyte");
				fc_v_ispad =
					LLVMBuildICmp(fc_b, LLVMIntEQ,
								  fc_v_possible_padbyte, l_int8_const(fc_lc, 0),
								  "ispadbyte");
				LLVMBuildCondBr(fc_b, fc_v_ispad,
								fc_attalignblocks[fc_attnum],
								fc_attstoreblocks[fc_attnum]);
			}
			else
			{
				LLVMBuildBr(fc_b, fc_attalignblocks[fc_attnum]);
			}

			LLVMPositionBuilderAtEnd(fc_b, fc_attalignblocks[fc_attnum]);

			/* 对齐代码的翻译（参见 TYPEALIGN()） */
			{
				LLVMValueRef fc_v_off_aligned;
				LLVMValueRef fc_v_off = l_load(fc_b, TypeSizeT, fc_v_offp, "");

				/* ((ALIGNVAL) - 1) */
				LLVMValueRef fc_v_alignval = l_sizet_const(fc_alignto - 1);

				/*((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) */
				LLVMValueRef fc_v_lh = LLVMBuildAdd(fc_b, fc_v_off, fc_v_alignval, "");

				/* ~((uintptr_t) ((ALIGNVAL) - 1)) */
				LLVMValueRef fc_v_rh = l_sizet_const(~(fc_alignto - 1));

				fc_v_off_aligned = LLVMBuildAnd(fc_b, fc_v_lh, fc_v_rh, "aligned_offset");

				LLVMBuildStore(fc_b, fc_v_off_aligned, fc_v_offp);
			}

			/*
			 * 由于对齐要么是不必要的，要么已经完成，我们
			 * 现在知道当前的对齐。这是安全的，因为该
			 * 值不用于varlena和可空列。
			 */
			if (fc_known_alignment >= 0)
			{
				Assert(fc_known_alignment != 0);
				fc_known_alignment = TYPEALIGN(fc_alignto, fc_known_alignment);
			}

			LLVMBuildBr(fc_b, fc_attstoreblocks[fc_attnum]);
			LLVMPositionBuilderAtEnd(fc_b, fc_attstoreblocks[fc_attnum]);
		}
		else
		{
			LLVMPositionBuilderAtEnd(fc_b, fc_attcheckalignblocks[fc_attnum]);
			LLVMBuildBr(fc_b, fc_attalignblocks[fc_attnum]);
			LLVMPositionBuilderAtEnd(fc_b, fc_attalignblocks[fc_attnum]);
			LLVMBuildBr(fc_b, fc_attstoreblocks[fc_attnum]);
		}
		LLVMPositionBuilderAtEnd(fc_b, fc_attstoreblocks[fc_attnum]);

		/*
		 * 如果已知当前偏移量是常量，则存储当前偏移量。这样可以使 LLVM
		 * 生成更好的代码。否则，LLVM无法推断出
		 * 由于先前解码列的跳转，偏移量可能是常量。
		 */
		if (fc_attguaranteedalign)
		{
			Assert(fc_known_alignment >= 0);
			LLVMBuildStore(fc_b, l_sizet_const(fc_known_alignment), fc_v_offp);
		}

		/* 计算后续列的对齐方式 */
		if (fc_att->attlen < 0)
		{
			/* 在可变长度字段之后无法保证任何对齐 */
			fc_known_alignment = -1;
			fc_attguaranteedalign = false;
		}
		else if (fc_att->attnotnull && fc_attguaranteedalign && fc_known_alignment >= 0)
		{
			/*
			 * 如果列的偏移量之前已知，则 NOT NULL &
			 * 固定宽度列可确保对齐方式只是
			 * 之前的对齐加上列宽。
			 */
			Assert(fc_att->attlen > 0);
			fc_known_alignment += fc_att->attlen;
		}
		else if (fc_att->attnotnull && (fc_att->attlen % fc_alignto) == 0)
		{
			/*
			 * 在长度为其对齐要求的倍数的 NOT NULL 固定宽度列之后，
			 * 我们知道下一个列的对齐至少与当前列的对齐相同。
			 */
			Assert(fc_att->attlen > 0);
			fc_known_alignment = fc_alignto;
			Assert(fc_known_alignment > 0);
			fc_attguaranteedalign = false;
		}
		else
		{
			fc_known_alignment = -1;
			fc_attguaranteedalign = false;
		}


		/* 计算从中加载数据的地址 */
		{
			LLVMValueRef fc_v_off = l_load(fc_b, TypeSizeT, fc_v_offp, "");

			fc_v_attdatap =
				l_gep(fc_b, LLVMInt8TypeInContext(fc_lc), fc_v_tupdata_base, &fc_v_off, 1, "");
		}

		/* 计算存储值的地址 */
		fc_v_resultp = l_gep(fc_b, TypeSizeT, fc_v_tts_values, &fc_l_attno, 1, "");

		/* 存储空字节（假） */
		LLVMBuildStore(fc_b, l_int8_const(fc_lc, 0),
					   l_gep(fc_b, TypeStorageBool, fc_v_tts_nulls, &fc_l_attno, 1, ""));

		/*
		 * 存储数据。对于 byval：数据副本复制值，扩展到 Datum 的
		 * 宽度，并存储。对于 byref 类型：存储指向数据的指针。
		 */
		if (fc_att->attbyval)
		{
			LLVMValueRef fc_v_tmp_loaddata;
			LLVMTypeRef fc_vartype = LLVMIntTypeInContext(fc_lc, fc_att->attlen * 8);
			LLVMTypeRef fc_vartypep = LLVMPointerType(fc_vartype, 0);

			fc_v_tmp_loaddata =
				LLVMBuildPointerCast(fc_b, fc_v_attdatap, fc_vartypep, "");
			fc_v_tmp_loaddata = l_load(fc_b, fc_vartype, fc_v_tmp_loaddata, "attr_byval");
			fc_v_tmp_loaddata = LLVMBuildZExt(fc_b, fc_v_tmp_loaddata, TypeSizeT, "");

			LLVMBuildStore(fc_b, fc_v_tmp_loaddata, fc_v_resultp);
		}
		else
		{
			LLVMValueRef fc_v_tmp_loaddata;

			/* 存储指针 */
			fc_v_tmp_loaddata =
				LLVMBuildPtrToInt(fc_b,
								  fc_v_attdatap,
								  TypeSizeT,
								  "attr_ptr");
			LLVMBuildStore(fc_b, fc_v_tmp_loaddata, fc_v_resultp);
		}

		/* 增加数据指针 */
		if (fc_att->attlen > 0)
		{
			fc_v_incby = l_sizet_const(fc_att->attlen);
		}
		else if (fc_att->attlen == -1)
		{
			fc_v_incby = l_call(fc_b,
							 llvm_pg_var_func_type("varsize_any"),
							 llvm_pg_func(fc_mod, "varsize_any"),
							 &fc_v_attdatap, 1,
							 "varsize_any");
			l_callsite_ro(fc_v_incby);
			l_callsite_alwaysinline(fc_v_incby);
		}
		else if (fc_att->attlen == -2)
		{
			fc_v_incby = l_call(fc_b,
							 llvm_pg_var_func_type("strlen"),
							 llvm_pg_func(fc_mod, "strlen"),
							 &fc_v_attdatap, 1, "strlen");

			l_callsite_ro(fc_v_incby);

			/* 为 NUL 字节添加 1 */
			fc_v_incby = LLVMBuildAdd(fc_b, fc_v_incby, l_sizet_const(1), "");
		}
		else
		{
			Assert(false);
			fc_v_incby = NULL;		/* 使编译器静默 */
		}

		if (fc_attguaranteedalign)
		{
			Assert(fc_known_alignment >= 0);
			LLVMBuildStore(fc_b, l_sizet_const(fc_known_alignment), fc_v_offp);
		}
		else
		{
			LLVMValueRef fc_v_off = l_load(fc_b, TypeSizeT, fc_v_offp, "");

			fc_v_off = LLVMBuildAdd(fc_b, fc_v_off, fc_v_incby, "increment_offset");
			LLVMBuildStore(fc_b, fc_v_off, fc_v_offp);
		}

		/*
		 * 跳转到下一个块，除非是最后一个可能的列，或者所有所需
		 * （可用）属性已经被提取。
		 */
		if (fc_attnum + 1 == fc_natts)
		{
			/* jump out */
			LLVMBuildBr(fc_b, fc_b_out);
		}
		else
		{
			LLVMBuildBr(fc_b, fc_attcheckattnoblocks[fc_attnum + 1]);
		}
	}


	/* 构建返回的块 */
	LLVMPositionBuilderAtEnd(fc_b, fc_b_out);

	{
		LLVMValueRef fc_v_off = l_load(fc_b, TypeSizeT, fc_v_offp, "");
		LLVMValueRef fc_v_flags;

		LLVMBuildStore(fc_b, l_int16_const(fc_lc, fc_natts), fc_v_nvalidp);
		fc_v_off = LLVMBuildTrunc(fc_b, fc_v_off, LLVMInt32TypeInContext(fc_lc), "");
		LLVMBuildStore(fc_b, fc_v_off, fc_v_slotoffp);
		fc_v_flags = l_load(fc_b, LLVMInt16TypeInContext(fc_lc), fc_v_flagsp, "tts_flags");
		fc_v_flags = LLVMBuildOr(fc_b, fc_v_flags, l_int16_const(fc_lc, TTS_FLAG_SLOW), "");
		LLVMBuildStore(fc_b, fc_v_flags, fc_v_flagsp);
		LLVMBuildRetVoid(fc_b);
	}

	LLVMDisposeBuilder(fc_b);

	return fc_v_deform_fn;
}
